/**
* Oxide
*
* Copyright (c) 2011 Dinosaur Kick Pty Ltd, All rights reserved.
*
* This source code is made available under the "Modified BSD" licensing arrangement.
* See license.txt for details.
*/
// ----------------------------------------------------------------------------
#include <boost/utility/addressof.hpp>
#include "oxide-common/comparator.hpp"
#include "oxide-common/is_empty.hpp"
#include "oxide-common/coalesce.hpp"
// ----------------------------------------------------------------------------
#ifndef O2_CURSOR_INC
#define O2_CURSOR_INC
namespace o2 {
namespace detail {
// ----------------------------------------------------------------------------

template <typename IteratorT>
struct default_cursor_incrementer
{
	IteratorT& operator() (IteratorT& iter) const
	{
		return ++iter;
	}
};

// ----------------------------------------------------------------------------
} // namespace detail
// ----------------------------------------------------------------------------

template
<
	typename IteratorT,
	typename IncrementerT = detail::default_cursor_incrementer<IteratorT>,
	typename ComparisonT = typename std::iterator_traits<IteratorT>::value_type,
	typename ComparatorT = comparator<typename std::iterator_traits<IteratorT>::value_type, ComparisonT>,
	typename EmptyPredicateT = is_empty<typename std::iterator_traits<IteratorT>::value_type>
>
class cursor
{
	public:
		typedef IteratorT iterator_type;
		typedef IncrementerT incrementer_type;
		typedef ComparisonT comparison_type;
		typedef ComparatorT comparator_type;
		typedef EmptyPredicateT empty_predicate_type;
		typedef typename std::iterator_traits<iterator_type>::value_type value_type;

		cursor(const iterator_type& begin, const iterator_type& end)
			: m_iter(begin)
			, m_end(end)
			{ }
			
		cursor(const iterator_type& begin, const iterator_type& end, const incrementer_type& incrementer)
			: cursor(begin, end)
			, m_incrementer(incrementer)
			{ }

		cursor(const iterator_type& begin, const iterator_type& end, const incrementer_type& incrementer, const comparator_type& comparator)
			: cursor(begin, end)
			, m_incrementer(incrementer)
			, m_comparator(comparator)
			{ }

		cursor(const iterator_type& begin, const iterator_type& end, const incrementer_type& incrementer, const comparator_type& comparator, const empty_predicate_type& empty_predicate)
			: cursor(begin, end)
			, m_incrementer(incrementer)
			, m_comparator(comparator)
			, m_empty_predicate(empty_predicate)
			{ }

		bool exhausted(void) const
			{ return m_iter == m_end; }
		operator bool (void) const
			{ return m_iter != m_end; }
		bool operator! (void) const
			{ return m_iter == m_end; }

		value_type get(void)
			{ iterator_type iter = m_iter; m_incrementer(m_iter); return *iter; }

		const value_type& peek(void) const
			{ return *m_iter; }
		virtual const value_type& operator* (void) const
			{ return *m_iter; }
		virtual const value_type* operator-> (void) const
			{ return boost::addressof(*m_iter); }

		/**
		* Advance to the next item.
		*
		* Returns false if cursor is exhausted.
		*/
		bool next(void)
			{ return m_incrementer(m_iter) != m_end; }

		/**
		* Advance to the next non-empty item.
		*
		* Returns false if cursor is exhausted.
		*/
		bool advance(void)
		{
			return m_incrementer(m_iter) != m_end
				&& skip_empty();
		}

		/**
		* Advance past any empty items.
		*
		* Returns false if cursor is exhausted.
		*/
		bool skip_empty(void)
		{
			while (m_iter != m_end && m_empty_predicate(*m_iter))
			{
				m_incrementer(m_iter);
			}
			return m_iter != m_end;
		}
		
		/**
		* Advance to the next item if the current item is equal to the given value.
		*
		* Returns true if the cursor is advanced.
		*/
		bool advance_if(const comparison_type& value)
		{
			if (m_comparator(*m_iter, value) == 0)
			{
				m_incrementer(m_iter);
				return true;
			}
			return false;
		}

		/**
		* Advance to the next item the current item is within the given range.
		*
		* Returns true if the cursor is advanced.
		*/
		bool advance_if(const comparison_type& min, const comparison_type& max)
		{
			if (m_comparator(*m_iter, min) >= 0 && m_comparator(*m_iter, max) <= 0)
			{
				m_incrementer(m_iter);
				return true;
			}
			return false;
		}

		/**
		* Advance to the next item the current item is within the given range.
		*
		* If advancing will occur the current value is written to the out parameter.
		*
		* Returns true if the cursor is advanced.
		*/
		bool advance_if(const comparison_type& min, const comparison_type& max, value_type& out)
		{
			if (m_comparator(*m_iter, min) >= 0 && m_comparator(*m_iter, max) <= 0)
			{
				out = *m_iter;
				m_incrementer(m_iter);
				return true;
			}
			return false;
		}

		/**
		* Advance to the next item that is equal to one of the given values.
		*/
		bool advance_to(const comparison_type& value)
		{
			for (; m_iter != m_end; m_incrementer(m_iter))
			{
				if (m_comparator(*m_iter, value) == 0)
				{
					return true;
				}
			}
			return false;
		}
		
		bool advance_to(const comparison_type& value0, const comparison_type& value1)
		{
			for (; m_iter != m_end; m_incrementer(m_iter))
			{
				if (m_comparator(*m_iter, value0) == 0 || m_comparator(*m_iter, value1) == 0)
				{
					return true;
				}
			}
			return false;
		}

		bool advance_to(const comparison_type& value0, const comparison_type& value1, const comparison_type& value2)
		{
			for (; m_iter != m_end; m_incrementer(m_iter))
			{
				if (m_comparator(*m_iter, value0) == 0 || m_comparator(*m_iter, value1) == 0 || m_comparator(*m_iter, value2) == 0)
				{
					return true;
				}
			}
			return false;
		}
		
		const incrementer_type& incrementer(void) const
		{
			return m_incrementer;
		}

	protected:
		iterator_type m_iter;
		const iterator_type m_end;
		incrementer_type m_incrementer;
		comparator_type m_comparator;
		empty_predicate_type m_empty_predicate;
};

// ----------------------------------------------------------------------------
} // namespace o2
#endif // O2_CURSOR_INC
// ----------------------------------------------------------------------------
